﻿using System;
using System.Reactive.Linq;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Input;

namespace ZOIL.Library.Behaviors
{
    [Export(typeof(PluginSelectionBehavior))]
    public class TouchSelectionBehavior : PluginSelectionBehavior
    {
        #region private fields

        private IDisposable _touchSelectionSubscription;

        #endregion

        #region private methods

        private IDisposable RegisterTouchEvents()
        {
            var touchMove = Observable.FromEventPattern<TouchEventArgs>(AssociatedObject, UIElement.TouchMoveEvent.Name);

            var touchDown = Observable.FromEventPattern<TouchEventArgs>(AssociatedObject, UIElement.TouchDownEvent.Name);

            var touchUp = Observable.FromEventPattern<TouchEventArgs>(AssociatedObject, UIElement.TouchUpEvent.Name);

            var touchMoves = from mm in touchMove
                             select mm.EventArgs.GetTouchPoint(null).Position;

            var touchDrag = from mlbd in touchDown.Select(evt =>
            {
                evt.EventArgs.Handled = true;
                return new SelectionHelper(evt.EventArgs.TouchDevice, new Selection(evt.EventArgs.GetTouchPoint(null).Position));
            }).Do(sh =>
                      {
                          StartSelection(sh.Selection);
                          AssociatedObject.CaptureTouch(sh.TouchDevice);
                      })
                            from md in touchMoves.Do(point => mlbd.Selection.Points.Add(point))
                            .TakeUntil(touchUp.Do(evt => mlbd.Selection.Points.Add(evt.EventArgs.GetTouchPoint(null).Position))
                            .Do(evt =>
                                    {
                                        evt.EventArgs.Handled = true;
                                        FinishSelection(mlbd.Selection);
                                        AssociatedObject.ReleaseTouchCapture(evt.EventArgs.TouchDevice);
                                    }))
                            select mlbd;

            return touchDrag.Select(sh => sh.Selection).Subscribe(ChangeSelection);
        }

        #endregion

        #region overrides

        protected override void OnIsEnabledChanged(bool oldIsSelectionEnabled, bool newIsSelectionEnabled)
        {
            if (newIsSelectionEnabled)
            {
                _touchSelectionSubscription = RegisterTouchEvents();
            }
            else
            {
                if (_touchSelectionSubscription != null)
                    _touchSelectionSubscription.Dispose();
            }
        }

        #endregion

        #region helper class

        private class SelectionHelper
        {
            public TouchDevice TouchDevice { get; private set; }
            public Selection Selection { get; private set; }

            public SelectionHelper(TouchDevice touchDevice, Selection selection)
            {
                TouchDevice = touchDevice;
                Selection = selection;
            }
        }

        #endregion
    }
}
